package
{
	import as3isolib.display.IsoSprite;
	import as3isolib.display.scene.IsoScene;
	
	import flash.display.Sprite;
	import flash.filters.GlowFilter;
	import flash.geom.Point;
	import flash.text.AntiAliasType;
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;
	import flash.text.TextFormat;

	public class Engine
	{
		private var buildingGrid:Array  = new Array(Render.gridSize*Render.gridSize);
		private var buildings:Array = new Array();
		public var cars:Array = new Array(Render.gridSize*Render.gridSize);
		private var mx:int=0,my:int=0;
		
		public var renderShit:Array = new Array(Render.gridSize*Render.gridSize);
		private var render:Render;
		private var sceneBuildings:Array = new Array();
		public var progressLayer:IsoSprite = new IsoSprite();
		private var progressBars:Array = new Array();
		public var popupTexts:Array = new Array();
		public function Engine(r:Sprite){
			render = r as Render;
		}

		public function calcMs(str:String):void{
			if (str == CONSTANTS.garageType){
				mx = 1;
				my = 2;
			}
			else if (str == CONSTANTS.factoryType){
				mx = 2;
				my = 3;
			}
			else if (str == CONSTANTS.generatorType){
				mx = 2;
				my = 2;
			}
			else if (str == CONSTANTS.siloType){
				mx = 1;
				my = 1;
			}
		}
		
		public function giveBuilding(x:int,y:int,str:String,buildingSprite:Animation,pr:Number):Building{
			calcMs(str);
			var b:Building;
			
			hideBuildings();
			for (var i:int = 0;i<mx;i++)
				for (var j:int = 0;j<my;j++){
					b = new Building(x,y,1,str,null);
					b.setMain(false);
					buildingGrid[(y-j)*Render.gridSize+x-i] = b;
				}
			b = new Building(x,y,pr,str,buildingSprite); 
			b.setMain(true);
			buildingGrid[y*Render.gridSize+x] = b;
			sceneBuildings.push(b);
			buildings.push(b);
			var pb:ProgressBar;
			if(str == CONSTANTS.factoryType) pb = new ProgressBar(this,b,8,(x+1)*Render.gridWidth,(1+y)*Render.gridWidth);
			else if(str == CONSTANTS.siloType) pb = new ProgressBar(this,b,10,(x+1)*Render.gridWidth,(1+y)*Render.gridWidth);
			else pb = new ProgressBar(this,b,5,(x+1)*Render.gridWidth,(1+y)*Render.gridWidth);
			progressBars.push(pb);
			progressLayer.addChild(pb);
			
			showBuildings();
			return b;
		}
		
		/**
		 * Force the scene to update, thus rearranging the ordering of buildings with correct layering.
		 */
		public function refreshScene():void{
			hideBuildings();
			showBuildings();
		}
		
		private function hideBuildings():void{
			if (render.scene.contains(progressLayer))render.scene.removeChild(progressLayer);
			for (var i:int = 0;i<sceneBuildings.length;i++)
				if (render.scene.contains((sceneBuildings[i]).image))
					render.scene.removeChild((sceneBuildings[i]).image);
		}
		
		private function showBuildings():void{
			for (var y=0;y<Render.gridSize;y++)
				for (var x = 0;x<=y;x++){
					var i = (y-x)*Render.gridSize+x;
					if (buildingGrid[i]!=null && (buildingGrid[i] as Building).isMain() && (buildingGrid[i] as Building).producing )
						render.scene.addChild((buildingGrid[i]).image);
				}
			for (var x = 0;x<Render.gridSize;x++){
				var c=0;
				for (var y = Render.gridSize-1;y>=x;y--){
					var i = y*Render.gridSize+(x+c);
					c+=1;
					if (buildingGrid[i]!=null && (buildingGrid[i] as Building).isMain() && (buildingGrid[i] as Building).producing )
						render.scene.addChild((buildingGrid[i]).image);
				}
			}
			
			
			render.scene.addChild(progressLayer);
		}
		
		/**
		 * Updates the graphics of each item currently residing in the progress layer (such
		 * as progress bars and popup text). Should be called by the render every frame.
		 */
		public function updateProgressLayer():void{
			var i:int;
			//progress bars
			for (i = 0;i<progressBars.length;i++){
				var p:ProgressBar = progressBars[i];
				if (p==null)continue;
				if (p.init)continue;
				p.updateGraphics();
			}
			
			//popup texts
			for (i = 0; i < popupTexts.length; i++){
				var text : PopupText = popupTexts[i];
				if (text == null) continue;
				if (text.complete){
					continue;
				}
				text.updateGraphics();
			}
		}
		public function levelUp(x:int,y:int):void{
			var b:Building = getMain(x,y);
			if (b==null)return;
			b.levelUp();
			render.upgradeSound.play();
		}
		
		public function addExp(i:int):void{
			render.expAmount += i;
			while(render.expAmount >= render.maxExpAmount){
				render.level++;
				render.lvlText.text = "LEVEL "+render.level;
				render.expAmount -= render.maxExpAmount;
				render.maxExpAmount *= 2;
				
				//check unlocks
				if(render.level == CONSTANTS.generatorLvlReq) render.generatorButt.setClickable(true);
				if(render.level == CONSTANTS.factoryLvlReq) render.factoryButt.setClickable(true);
				if(render.level == CONSTANTS.siloLvlReq) render.siloButt.setClickable(true);
				if(render.level == CONSTANTS.garageLvlReq) render.garageButt.setClickable(true);
				//make noise n shit
				render.upgradeSound.play();
			}
			
			//create popup text
			
			//exp gain sound
		}
		
		public function giveCar(x:int,y:int):void{
			calcMs(CONSTANTS.garageType);
			var b:Car;
			b = new Car(x,y);
			b.setColour(0xFF0000);
			/*
			for (var i:int = 0;i<mx;i++)
				for (var j:int = 0;j<my;j++){
					cars[(y-j)*Render.gridSize+x-i] = b;
				}
			*/
			cars[y*Render.gridSize+x]=b;
		}
		
		/**
		 * A function to be called by the render every frame, to calculate the resources generated by
		 * each building on the grid that is able to generate something. The resource generated is sent to
		 * the building, where it can be collected at a further time with the 'collect' command upon clicking
		 * on said building.
		 */
		public function calcEarnedResources():void{
			for (var i:int = 0;i<buildingGrid.length;i++){
				if (buildingGrid[i]!=null  && (buildingGrid[i] as Building).isMain() && (buildingGrid[i] as Building).producing && (buildingGrid[i] as Building).getType()!=CONSTANTS.garageType)
					(buildingGrid[i] as Building).generateResources();
				if (buildingGrid[i]!=null  && (buildingGrid[i] as Building).isMain() && (buildingGrid[i] as Building).producing && (buildingGrid[i] as Building).getType()==CONSTANTS.garageType && (buildingGrid[i] as Building).hasCar)
					(buildingGrid[i] as Building).generateResources();
			}
			return;
		}
		
		public function checkEnoughResources(str:String,currentEnergy:int):Boolean{
			if (str=="Garage"){
				return currentEnergy>=CONSTANTS.garageCost;
			}
			else if (str=="powerFarm"){
				return currentEnergy>=CONSTANTS.generatorCost;
			}
			else if (str=="Factory"){
				return currentEnergy>=CONSTANTS.factoryCost;
			}
			else if (str=="Silo"){
				return currentEnergy>=CONSTANTS.siloCost;
			}
			else return false;
		}
		public function canPlace(object:String,x:int,y:int):Boolean{
			calcMs(object);
			for (var i:int = 0;i<mx;i++)
				for (var j:int = 0;j<my;j++){
					if (buildingGrid[(y-j)*Render.gridSize+x-i]!=null || y-j<0 || x-i<0){
						return false;
					}
				}
			return true;
		}
		
		public function getCar(x:int,y:int):Car{
			return cars[y*Render.gridSize+x];
		}
		
		/**
		 * Gets the name of the type of building on the specified grid location.
		 */
		public function getType(x:int,y:int):String{
			var b:Building = buildingGrid[(y)*Render.gridSize+x] as Building;
			if (b==null)return null;
			return b.getType();
		}
		
		/**
		 * Returns the amount of resource generated by the building at the given
		 * co-ordinates.
		 * @param x: the x position of the building on the grid
		 * @param y: the y position of the building on the grid
		 * @return Amount of resource generated. If there is no building at the
		 * provided location, this will return zero. As this only returns an int, extra
		 * checks will need to be done to determine what type of resource the building
		 * is meant to generate.
		 */
		public function getResourcesFromBuilding(x:int, y:int):int{
			var b:Building = getMain(x,y);
			if (b==null) return 0;
			return b.collectResources();
		}
		
		public function getMain(x:int, y:int):Building{
			var b:Building = buildingGrid[(y)*Render.gridSize+x] as Building;
			if(b == null) return null;
			if(b.isMain()) return b;
			return buildingGrid[(b.y)*Render.gridSize + b.x] as Building;
		}
		
		public function save(energy:int):void{
			
		}
		public function createCar():void{
			for (var i:int = 0;i<buildings.length;i++){
				var b :Building = buildings[i] as Building;
				if (b.getType() == CONSTANTS.garageType && b.hasCar==false){
					giveCar(b.x,b.y);
					b.hasCar=true;
					b.image.setSprite(1);
					break;
				}
			}
		}
		
		
		
	}
}